React hook form(4) - controlled component & forwardRef


Posted by TempuraEngineer on 2023-08-20

目錄


在前幾篇有提到Controller + control可以幫助你把包裝得很深的組件和react hook form做連結

那是否有Controller + control以外的方法呢🤔

這或許要先了解一下react hook form的一大重點uncontrolled component

而當表單內的欄位是uncontrolled component時,會需要透過ref來操作DOM,進而控制表單


ref

在React18,ref分為幾種,通常被用在你想要組件記得一些資料,但是又不想要每次資料更新時組件都會re-render時

  • callback ref
    組件掛載好後,React會呼叫它,然後取得DOM元素(不需要selector)
    react-hook-form的register回傳的ref就是這種
  • ref object
    使用createRef、useRef可以建立ref物件,使用ref.current可以取得值
    兩者的差異在於前者被呼叫會回傳一個新的物件(reference不同),後者則是每次渲染都回傳同個物件(reference一樣)
  • forwardRef
    forwardRef是接收functional component的function,透過它可以將子組件的ref暴露給父組件
    常見於深度包裝的組件或HOC


包裝很深的組件怎麼註冊

一些包裝得很深的組件(ex: MUI的組件,或者自己做的組件)配合react-hook-form使用時,可能會遇到明明畫面上顯示的值改變了,但實際上form的值沒有改變的問題,這是因為沒有成功把register回傳值傳給組件

根據官方文件,只要正確地暴露ref給上層組件,就能運作

Props Name: ref
Type: React.Ref
Description: Input reference for hook form to register.

所以要做的就是將組件用forwardRef包起來

const Select = forwardRef(
  <T extends string>(
    { label, children, ...resetProps }: MuiSelectProps<T>,
    ref: ForwardedRef<HTMLInputElement>
  ) => {
    return (
      <>
        <InputLabel shrink style={{ textAlign: "left" }}>
          {label}
        </InputLabel>
        <MuiSelect ref={ref} {...resetProps}>
          {children}
        </MuiSelect>
      </>
    );
  }
);

用起來則會像這樣

<Select
        label="Education"
        displayEmpty
        renderValue={(selected) => {
          return <Typography>{selected}</Typography>;
        }}
        {...register("highestEducation")}
      >
        {educationOptions.map(({ label, value }) => (
          <MenuItem value={value} key={value} style={{ textAlign: "left" }}>
            {label}
          </MenuItem>
        ))}
      </Select>


參考資料

forwardRef
Referencing Values with Refs
A complete guide to React refs
Things you need to know about React ref
React hook form - register


#react-hook-form #forwardRef #controlled component







Related Posts

Angular17 基於 Standalone 專案載入 Material Symbols (Google Icon)

Angular17 基於 Standalone 專案載入 Material Symbols (Google Icon)

JavaScript 變數( Variable )的辣

JavaScript 變數( Variable )的辣

Linux Command 命令列指令與基本操作入門教學

Linux Command 命令列指令與基本操作入門教學


Comments